#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

#include <SDL2/SDL.h>

#include "utils.h"
#include "patch.h"

SDL_Renderer *SDL_SS2D_GetRenderer(void *this)
{
    int8_t *driverdata = *(int8_t **)((int8_t *)this + 0);
    SDL_Renderer **renderers = *(SDL_Renderer ***)(driverdata + 128);
    return renderers[0];
}

SDL_Surface *SDL_SS2D_GetRenderSurface(void *this)
{
    SDL_Surface *surface = *(SDL_Surface **)((int8_t *)this + 1 * 4);
    return surface;
}

SDL_Texture *SDL_SS2D_GetRenderTexture(void *this)
{
    SDL_Texture *texture = *(SDL_Texture **)((int8_t *)this + 2 * 4);
    return texture;
}

int SDL_SS2D_RenderUpdate(void *this)
{
    int result = 0;

    SDL_Renderer *renderer = SDL_SS2D_GetRenderer(this);
    SDL_Surface *main_surface = SDL_SS2D_GetRenderSurface(this);
    SDL_Texture *main_texture = SDL_SS2D_GetRenderTexture(this);

    result = *((_BYTE *)this + 147);
    if (result)
    {
        *((_BYTE *)this + 147) = 0;

        if (main_texture && main_surface && main_surface->pixels)
        {
            //{ // Now no need to do this:
            // SDL_UpperBlit(main_surface, 0, SS2D_conversion_surface, 0);
            // SDL_UpdateTexture(main_texture, 0, SS2D_conversion_surface->pixels, SS2D_conversion_surface->pitch);
            //}
            SDL_UpdateTexture(main_texture, 0, main_surface->pixels, main_surface->pitch);

            SDL_RenderClear(renderer);
            if (*SS2D_bg_texture)
                SDL_RenderCopy(renderer, *SS2D_bg_texture, 0, 0);
            result = SDL_RenderCopy(renderer, main_texture, 0, SS2D_render_dst_rect);
            SDL_RenderPresent_soloader(renderer);
        }
    }

    return result;
}

int SDL_SS2D_Update(void *this)
{
    int result;

    // debugPrintf("SDL_SS2D_Update: this: %p\n", this);

    result = *(_BYTE *)(this + 146);
    *((_BYTE *)this + 147) = 1;

    if (!result)
        return SDL_SS2D_RenderUpdate(this);

    return result;
}

SDL_Surface *SDL_SS2D_LoadImageFile(void *this, const char *filePath)
{
    SDL_Surface *surface = NULL;

    SDL_RWops *rwops = Get_RWops(filePath);
    if (rwops)
        surface = IMG_Load_RW(rwops, 1);

    debugPrintf("SDL_SS2D_LoadImageFile: path: %s, return: %p\n", filePath, surface);
    return surface;
}

int initPatchSdlSs2d()
{
    hook_addr(so_symbol(&so_mod, "_ZN8SDL_SS2D13LoadImageFileEPKc"), (uintptr_t)&SDL_SS2D_LoadImageFile);
    hook_addr(so_symbol(&so_mod, "_ZN8SDL_SS2D13ReanderUpdateEv"), (uintptr_t)&SDL_SS2D_RenderUpdate);
    hook_addr(so_symbol(&so_mod, "_ZN8SDL_SS2D6UpdateEv"), (uintptr_t)&SDL_SS2D_Update);

    return 0;
}